home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1983 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that this notice is preserved and that due credit is given
- * to the University of California at Berkeley. The name of the University
- * may not be used to endorse or promote products derived from this
- * software without specific prior written permission. This software
- * is provided ``as is'' without express or implied warranty.
- */
-
- #ifndef lint
- static char sccsid[] = "@(#)measure.c 2.5 (Berkeley) 12/23/87";
- #endif /* not lint */
-
- #include "globals.h"
- #include <protocols/timed.h>
- #include <netinet/in_systm.h>
- #include <netinet/ip.h>
- #include <netinet/ip_icmp.h>
-
- #define BIASP 43199999
- #define BIASN -43200000
- #define MODULO 86400000
- #define PROCESSING_TIME 5 /* ms. to reduce error in measurement */
-
- #define PACKET_IN 1024
-
- extern int id;
- int measure_delta;
- extern int sock_raw;
- static n_short seqno = 0;
-
- /*
- * Measures the differences between machines' clocks using
- * ICMP timestamp messages.
- */
-
- measure(wait, addr)
- struct timeval *wait;
- struct sockaddr_in *addr;
- {
- int length;
- int status;
- int msgcount, trials;
- int cc, count;
- fd_set ready;
- long sendtime, recvtime, histime;
- long min1, min2, diff;
- register long delta1, delta2;
- struct timeval tv1, tout;
- u_char packet[PACKET_IN], opacket[64];
- register struct icmp *icp = (struct icmp *) packet;
- register struct icmp *oicp = (struct icmp *) opacket;
- struct ip *ip = (struct ip *) packet;
-
- min1 = min2 = 0x7fffffff;
- status = HOSTDOWN;
- measure_delta = HOSTDOWN;
-
- /* empties the icmp input queue */
- FD_ZERO(&ready);
- empty:
- tout.tv_sec = tout.tv_usec = 0;
- FD_SET(sock_raw, &ready);
- if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) {
- length = sizeof(struct sockaddr_in);
- cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
- (struct sockaddr_in *)NULL, &length);
- if (cc < 0)
- return(-1);
- goto empty;
- }
-
- /*
- * To measure the difference, select MSGS messages whose round-trip
- * time is smaller than RANGE if ckrange is 1, otherwise simply
- * select MSGS messages regardless of round-trip transmission time.
- * Choose the smallest transmission time in each of the two directions.
- * Use these two latter quantities to compute the delta between
- * the two clocks.
- */
-
- length = sizeof(struct sockaddr_in);
- oicp->icmp_type = ICMP_TSTAMP;
- oicp->icmp_code = 0;
- oicp->icmp_cksum = 0;
- oicp->icmp_id = id;
- oicp->icmp_rtime = 0;
- oicp->icmp_ttime = 0;
- FD_ZERO(&ready);
- msgcount = 0;
- for (trials = 0; msgcount < MSGS && trials < TRIALS; ++trials) {
- oicp->icmp_seq = ++seqno;
- oicp->icmp_cksum = 0;
-
- tout.tv_sec = wait->tv_sec;
- tout.tv_usec = wait->tv_usec;
-
- (void)gettimeofday (&tv1, (struct timezone *)0);
- sendtime = oicp->icmp_otime = (tv1.tv_sec % (24*60*60)) * 1000
- + tv1.tv_usec / 1000;
- oicp->icmp_cksum = in_cksum((u_short *)oicp, sizeof(*oicp));
-
- count = sendto(sock_raw, (char *)opacket, sizeof(*oicp), 0,
- addr, sizeof(struct sockaddr_in));
- if (count < 0) {
- status = UNREACHABLE;
- return(-1);
- }
- for (;;) {
- FD_SET(sock_raw, &ready);
- if ((count = select(FD_SETSIZE, &ready, (fd_set *)0,
- (fd_set *)0, &tout)) <= 0)
- break;
- cc = recvfrom(sock_raw, (char *)packet, PACKET_IN, 0,
- (struct sockaddr_in *)NULL, &length);
- (void)gettimeofday(&tv1, (struct timezone *)0);
- if (cc < 0)
- return(-1);
- icp = (struct icmp *)(packet + (ip->ip_hl << 2));
- if((icp->icmp_type == ICMP_TSTAMPREPLY) &&
- icp->icmp_id == id && icp->icmp_seq == seqno)
- break;
- }
- if (count <= 0)
- continue; /* resend */
- recvtime = (tv1.tv_sec % (24*60*60)) * 1000 +
- tv1.tv_usec / 1000;
- diff = recvtime - sendtime;
- /*
- * diff can be less than 0 aroud midnight
- */
- if (diff < 0)
- continue;
- msgcount++;
- histime = ntohl((u_long)icp->icmp_rtime);
- /*
- * a hosts using a time format different from
- * ms. since midnight UT (as per RFC792) should
- * set the high order bit of the 32-bit time
- * value it transmits.
- */
- if ((histime & 0x80000000) != 0) {
- status = NONSTDTIME;
- break;
- }
- status = GOOD;
- delta1 = histime - sendtime;
- /*
- * Handles wrap-around to avoid that around
- * midnight small time differences appear
- * enormous. However, the two machine's clocks
- * must be within 12 hours from each other.
- */
- if (delta1 < BIASN)
- delta1 += MODULO;
- else if (delta1 > BIASP)
- delta1 -= MODULO;
- delta2 = recvtime - histime;
- if (delta2 < BIASN)
- delta2 += MODULO;
- else if (delta2 > BIASP)
- delta2 -= MODULO;
- if (delta1 < min1)
- min1 = delta1;
- if (delta2 < min2)
- min2 = delta2;
- if (diff < RANGE) {
- min1 = delta1;
- min2 = delta2;
- break;
- }
- }
-
- /*
- * If no answer is received for TRIALS consecutive times,
- * the machine is assumed to be down
- */
- if (status == GOOD) {
- measure_delta = (min1 - min2)/2 + PROCESSING_TIME;
- }
- return(status);
- }
-